﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace ProjectManagement.TFS
{
    public class TfsUtility
    {
        public List<string> GetTfsServerNamesCached()
        {
            List<string> serverNames = new List<string>();
            string mapXmlFilePath = Path.Combine(TeamFoundationServer.ClientCacheDirectory, "ServerMap.xml");
            if (File.Exists(mapXmlFilePath))
            {
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(mapXmlFilePath);
                XmlNodeList serverNodes = xDoc.SelectNodes("//Entry/Key");
                if (serverNodes != null && serverNodes.Count > 0)
                {
                    foreach (XmlNode serverNode in serverNodes)
                    {
                        string entryValue = serverNode.InnerText;
                        Regex entryRegex = new Regex("http://([^/:]+):(\\d+)/|https://([^/:]+):(\\d+)");
                        Match entryMatch = entryRegex.Match(entryValue);
                        if (entryMatch.Success)
                        {
                            serverNames.Add(entryMatch.Groups[1].Value);
                        }
                    }
                }
            }
            return serverNames;
        }

        public List<TeamProject> GetProjectNames(string tfsServerName)
        {
            List<TeamProject> projs = new List<TeamProject>();
            TeamFoundationServer tfs = new TeamFoundationServer(tfsServerName);
            try
            {
                tfs.Authenticate();
            }
            catch
            {
                tfs =
                    new TeamFoundationServer(tfsServerName, new NetworkCredential("Administrator", "xiaodong", "server"));
            }
            VersionControlServer vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
            TeamProject[] teamProjs = vcs.GetAllTeamProjects(false);

            if (teamProjs != null && teamProjs.Length > 0)
            {
                projs.AddRange(teamProjs);
            }
            return projs;
        }

        public Workspace GetCurrentWorkspace(string teamServerName)
        {
            TeamFoundationServer tfs = new TeamFoundationServer(teamServerName);
            try
            {
                tfs.Authenticate();
            }
            catch
            {
                tfs =
                    new TeamFoundationServer(teamServerName, new NetworkCredential("Administrator", "xiaodong", "server"));
            }
            VersionControlServer versionControl = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
            Workspace workspace = workspace = versionControl.GetWorkspace(Environment.MachineName, versionControl.AuthenticatedUser);
            return workspace;
        }

        public void CheckoutLatestVersion(string teamServerName, string projName)
        {
            TeamFoundationServer tfs = new TeamFoundationServer(teamServerName);
            try
            {
                tfs.Authenticate();
            }
            catch
            {
                tfs =
                    new TeamFoundationServer(teamServerName, new NetworkCredential("Administrator", "xiaodong", "server"));
            }
            VersionControlServer versionControl = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
            Workspace workspace = versionControl.GetWorkspace(Environment.MachineName, versionControl.AuthenticatedUser);
            if (workspace.IsLocal)
            {
                workspace.Get();
                workspace.PendEdit(string.Format("$/{0}", projName), RecursionType.Full);
            }
            else
            {
                throw new Exception(string.Format("the specified project {0} is not mapped to local machine", projName));
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="teamServerName"></param>
        /// <param name="teamProjName"></param>
        /// <param name="workspace"></param>
        /// <returns>map server path to list of file change histories</returns>
        public Dictionary<string, List<FileChangeHistory>> GetAllFilesWithTeamProject(string teamServerName, string teamProjName, out Workspace workspace)
        {
            Dictionary<string, List<FileChangeHistory>> items = new Dictionary<string, List<FileChangeHistory>>();
            TeamFoundationServer tfs = new TeamFoundationServer(teamServerName);
            try
            {
                tfs.Authenticate();
            }
            catch
            {
                tfs =
                    new TeamFoundationServer(teamServerName, new NetworkCredential("Administrator", "xiaodong", "server"));
            }
            VersionControlServer versionControl = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
            workspace = versionControl.GetWorkspace(Environment.MachineName, versionControl.AuthenticatedUser);
            if (workspace.IsLocal)
            {
                //workspace.Get();
                //workspace.PendEdit(string.Format("$/{0}", teamProjName), RecursionType.Full);
                // VersionControlPath.Combine(string.Format("$/{0}", teamProjName), "*");
            }
            else
            {
                throw new Exception("You must manually map team project to local workspace first");
            }
            try
            {
                string localProjPath = workspace.GetLocalItemForServerItem(string.Format("$/{0}", teamProjName));
                IEnumerable ienumerable =
                    versionControl.QueryHistory(localProjPath, VersionSpec.Latest, 0, RecursionType.Full,
                                                tfs.AuthenticatedUserName,
                                                VersionSpec.ParseSingleSpec(
                                                    "D" + (new DateTime(2000, 1, 1)).ToString(),
                                                    tfs.AuthenticatedUserName),
                                                VersionSpec.ParseSingleSpec("D" + DateTime.Now.ToString(),
                                                                            tfs.AuthenticatedUserName),
                                                int.MaxValue,
                                                true,
                                                false);
                foreach (Changeset changeSetItem in ienumerable)
                {
                    foreach (Change changedFile in changeSetItem.Changes)
                    {
                        string serverPath = changedFile.Item.ServerItem;
                        if (!items.ContainsKey(serverPath))
                        {
                            List<FileChangeHistory> changeHistories = new List<FileChangeHistory>();
                            FileChangeHistory fileHistory = new FileChangeHistory();
                            fileHistory.ChangeSetID = changeSetItem.ChangesetId;
                            fileHistory.Comment = changeSetItem.Comment;
                            fileHistory.Commiter = changeSetItem.Committer;
                            fileHistory.TimeStamp = changeSetItem.CreationDate;
                            fileHistory.ChangeType = changedFile.ChangeType.ToString();
                            int encoding = changedFile.Item.Encoding;
                            if (encoding == 1252 || encoding == 65001 || encoding == 1200)
                            {
                                string tmpFilePath = Path.GetTempFileName();
                                changedFile.Item.DownloadFile(tmpFilePath);
                                int lineCount = this.GetFileLineCount(tmpFilePath);
                                File.Delete(tmpFilePath);
                                fileHistory.SourceCodeLineCount = lineCount;
                            }
                            else
                            {
                                fileHistory.SourceCodeLineCount = 0;
                            }

                            changeHistories.Add(fileHistory);
                            items.Add(serverPath, changeHistories);
                        }
                        else
                        {
                            List<FileChangeHistory> changeHistories = items[serverPath];
                            FileChangeHistory fileHistory = new FileChangeHistory();
                            fileHistory.ChangeSetID = changeSetItem.ChangesetId;
                            fileHistory.Comment = changeSetItem.Comment;
                            fileHistory.Commiter = changeSetItem.Committer;
                            fileHistory.TimeStamp = changeSetItem.CreationDate;
                            fileHistory.ChangeType = changedFile.ChangeType.ToString();
                            int encoding = changedFile.Item.Encoding;
                            if (encoding == 1252 || encoding == 65001 || encoding == 1200)
                            {
                                string tmpFilePath = Path.GetTempFileName();
                                changedFile.Item.DownloadFile(tmpFilePath);
                                int lineCount = this.GetFileLineCount(tmpFilePath);
                                File.Delete(tmpFilePath);
                                fileHistory.SourceCodeLineCount = lineCount;
                            }
                            else
                            {
                                fileHistory.SourceCodeLineCount = 0;
                            }
                            changeHistories.Add(fileHistory);
                            items[serverPath] = changeHistories;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            return items;
        }

        private int GetFileLineCount(string filePath)
        {
            int lineCount = 0;
            if (File.Exists(filePath))
            {
                StreamReader reader = new StreamReader(filePath);
                while (!reader.EndOfStream)
                {
                    string line = reader.ReadLine();
                    if (line.Trim().Length > 0)
                    {
                        lineCount++;
                    }
                }
                reader.Close();
            }
            return lineCount;
        }

        public string GetApplicationName()
        {
            return TeamFoundationServer.ApplicationName;
        }

        #region tasks
        public static void CreateTask(TeamFoundationServer tfs, string teamProjName, 
            string taskName, string desc, 
            string owner, DateTime startTime, TimeSpan duration)
        {
            WorkItemStore itemStore = new WorkItemStore(tfs);
            Project proj = itemStore.Projects[teamProjName];
            WorkItemType wiType = proj.WorkItemTypes["task"];
            WorkItem wItem = new WorkItem(wiType);
            wItem.Description = desc;
            wItem.Title = taskName;
            // wItem.CreatedBy = owner;
            wItem.Save();
        }

        public static List<WorkItem> GetActiveProjectTasks(
            TeamFoundationServer tfs, string tfProjName, string owner)
        {
            List<WorkItem> activeTasks = new List<WorkItem>();
            WorkItemStore itemStore = new WorkItemStore(tfs);
            WorkItemCollection wic = itemStore.Query(
                string.Format("SELECT [System.Id], [System.WorkItemType]," +
                " [System.State], [System.AssignedTo], [System.Title] " +
                " FROM WorkItems " +
                " WHERE [System.TeamProject] = '{0}' and " +
                "[System.AssignedTo='{1}' " +
                "ORDER BY [System.WorkItemType], [System.Id]", 
                tfProjName, owner));
            Project proj = itemStore.Projects[tfProjName];
            WorkItemType wiType = proj.WorkItemTypes["task"];
            foreach (WorkItem wi in wic)
            {
                if (wi.Type == wiType && wi.IsOpen)
                {
                    activeTasks.Add(wi);
                }
            }

            return activeTasks;
        }
        #endregion

    }
}
